package org.jeecg.modules.car.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.mail.imap.protocol.BODY;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.api.vo.ForeignResult;
import org.jeecg.common.api.vo.ShParkingResult;
import org.jeecg.common.constant.RedisKeyConstant;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SHA1Util;
import org.jeecg.common.util.StringUtils;
import org.jeecg.entity.car.CarOrder;
import org.jeecg.entity.car.CarParkingRecord;
import org.jeecg.modules.car.entity.CarParkInfo;
import org.jeecg.modules.car.service.*;
import org.jeecg.modules.system.util.RestTemplateUtil;
import org.jeecg.vo.car.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

/**
 * @Description: 外部系统-对接上海市公共停车信息平台
 * @Author: liurui
 * @Date:   2021-05-13
 */
@Slf4j
@Service
public class ForeignCarShParkingService {

    @Autowired
    private RestTemplateUtil restTemplateUtil;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private ICarParkInfoService parkInfoService;
    @Autowired
    private ICarParkingRecordService recordService;

    @Value("${foreign-os.sh-parking}")  // http://parktest2.jtcx.sh.cn:80 测试环境
    private String outOsShParking;


    /**
     * 查询上传记录 - 测试环境使用
     * @return
     */
    public ShParkingResult query(CarParkInfo carParkInfo){
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        String url = outOsShParking + "service/parking/query/data/" + carParkInfo.getSuperviseParkingId();
        url = wrapperUrl(url,curTime,carParkInfo.getSuperviseAppId(),carParkInfo.getSupervisePassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,carParkInfo.getSupervisePassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return ShParkingResult.ok(jsonObject.toJSONString());
        }
        return ShParkingResult.error(jsonObject.toJSONString());
    }

    /**
     * 车辆入场
     * @param arriveReq
     * @return
     */
    public Boolean arrive(ForeignCarShArriveReq arriveReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("seq",getSeq(arriveReq.getParkingId()));
        paramMap.put("plateId", arriveReq.getPlateId());
        paramMap.put("vehicleType",arriveReq.getVehicleType());
        paramMap.put("laneType",arriveReq.getLaneType());
        paramMap.put("freeBerth",arriveReq.getFreeBerth());
        paramMap.put("parkType",arriveReq.getParkType());
        paramMap.put("dataTime", curTime);
        String url = outOsShParking + "/service/parking/data/parkplot/arrive/" + arriveReq.getParkingId();
        url = wrapperUrl(url,curTime,arriveReq.getAppId(),arriveReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,arriveReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return true;
        }
        return false;
    }

    /**
     * 车辆离场
     * @param leaveReq
     * @return
     */
    public Boolean leave(ForeignCarShLeaveReq leaveReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("seq",getSeq(leaveReq.getParkingId()));
        paramMap.put("plateId", leaveReq.getPlateId());
        paramMap.put("vehicleType",leaveReq.getVehicleType());
        paramMap.put("laneType",leaveReq.getLaneType());
        paramMap.put("freeBerth",leaveReq.getFreeBerth());
        paramMap.put("parkType",leaveReq.getParkType());
        paramMap.put("dataTime", curTime);
        paramMap.put("parkingTime",leaveReq.getParkingTime());
        paramMap.put("payMoney",leaveReq.getPayMoney());
        paramMap.put("payType",leaveReq.getPayType());
        String url = outOsShParking + "service/parking/data/parkplot/leave/" + leaveReq.getParkingId();
        url = wrapperUrl(url,curTime,leaveReq.getAppId(),leaveReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,leaveReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return true;
        }
        return false;
    }

    /**
     * 心跳检测批量 -  供定时任务调用
     */
    public void heartbeatBatch(){
       List<CarParkInfo> parkInfoList =  parkInfoService.findShParking();
       int success = 0 ,error = 0;
       for (CarParkInfo parkInfo: parkInfoList){
           ForeignCarShHeartbeatReq heartbeatReq = new ForeignCarShHeartbeatReq();
           heartbeatReq.setParkingId(parkInfo.getSuperviseParkingId());
           heartbeatReq.setAppId(parkInfo.getSuperviseAppId());
           heartbeatReq.setPassword(parkInfo.getSupervisePassword());
           String arriveKey = RedisKeyConstant.CAR_COUNTER_ARRIVE + parkInfo.getId();
           Object totalArrive =  redisUtil.get(arriveKey);
           heartbeatReq.setTotalArrived(0);
           if ( totalArrive != null){
               heartbeatReq.setTotalArrived((int)totalArrive);
           }
           String leaveKey = RedisKeyConstant.CAR_COUNTER_LEAVE + parkInfo.getId();
           Object totalLeave = redisUtil.get(leaveKey);
           heartbeatReq.setTotalLeft(0);
           if (totalLeave != null){
               heartbeatReq.setTotalLeft((int)totalLeave);
           }
           String freeKey = RedisKeyConstant.CAR_COUNTER_FREE + parkInfo.getId();
           Object freeBerth = redisUtil.get(freeKey);
           heartbeatReq.setFreeBerth(0);
           if (freeBerth != null){
               heartbeatReq.setFreeBerth((int)freeBerth);
           }
           try{
               boolean status = this.heartbeat(heartbeatReq);
               if (status){
                   success++;
               }else {
                   error++;
               }
           }catch (Exception e){
               log.error("心跳",e);
           }
       }
       log.info("心跳上传共计:{}条,成功:{},失败:{}",parkInfoList.size(),success,error);
    }


    /**
     * 心跳检测
     * @param heartbeatReq
     * @return
     */
    public Boolean heartbeat(ForeignCarShHeartbeatReq heartbeatReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("totalArrived", heartbeatReq.getTotalArrived());
        paramMap.put("totalLeft",heartbeatReq.getTotalLeft());
        paramMap.put("freeBerth",heartbeatReq.getFreeBerth());
        paramMap.put("dataTime", curTime);
        String url = outOsShParking + "service/parking/manage/parkplot/heartbeat/" + heartbeatReq.getParkingId();
        url = wrapperUrl(url,curTime,heartbeatReq.getAppId(),heartbeatReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,heartbeatReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return true;
        }
        return false;
    }

    /**
     * 数据补传
     * @param resendReq
     * @return
     */
    public boolean resend(ForeignCarShResendReq resendReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        List<Map<String,Object>> arriveList =  new ArrayList<>();
        List<Map<String,Object>> leaveList = new ArrayList<>();
        if (arriveList.size() > 0){
            paramMap.put("arrive",arriveList);
        }
        if (leaveList.size() > 0){
            paramMap.put("leave",leaveList);
        }
        long curTime = Calendar.getInstance().getTimeInMillis();
        for (ForeignCarShArriveReq arriveReq:resendReq.getArriveList()){
            Map<String,Object> arriveMap = new LinkedHashMap<>();
            arriveMap.put("seq",getSeq(resendReq.getParkingId()));
            arriveMap.put("plateId", arriveReq.getPlateId());
            arriveMap.put("vehicleType",arriveReq.getVehicleType());
            arriveMap.put("laneType",arriveReq.getLaneType());
            arriveMap.put("freeBerth",arriveReq.getFreeBerth());
            arriveMap.put("parkType",arriveReq.getParkType());
            arriveMap.put("dataTime", curTime);
            arriveList.add(arriveMap);
        }
        for (ForeignCarShLeaveReq leaveReq:resendReq.getLeaveList()){
            Map<String,Object> leaveMap = new LinkedHashMap<>();
            leaveMap.put("seq",getSeq(resendReq.getParkingId()));
            leaveMap.put("plateId", leaveReq.getPlateId());
            leaveMap.put("vehicleType",leaveReq.getVehicleType());
            leaveMap.put("laneType",leaveReq.getLaneType());
            leaveMap.put("freeBerth",leaveReq.getFreeBerth());
            leaveMap.put("parkType",leaveReq.getParkType());
            leaveMap.put("dataTime", curTime);
            leaveMap.put("parkingTime",leaveReq.getParkingTime());
            leaveMap.put("payMoney",leaveReq.getPayMoney());
            leaveMap.put("payType",leaveReq.getPayType());
            leaveList.add(leaveMap);
        }
        String url = outOsShParking + "service/parking/data/resend/" + resendReq.getParkingId();
        url = wrapperUrl(url,curTime,resendReq.getAppId(),resendReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,resendReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return true;
        }
        return false;
    }

    /**
     * 停车缴费减免 No5.3.1
     * @return
     */
    public BigDecimal reduces(CarParkInfo carParkInfo, String plateId, Date inTime) {
        ForeignCarShTempCostReq tempCostReq = new ForeignCarShTempCostReq();
        if (carParkInfo != null && StringUtils.isNotBlank(carParkInfo.getSuperviseParkingId())){
            tempCostReq.setAppId(carParkInfo.getSuperviseAppId());
            tempCostReq.setPassword(carParkInfo.getSupervisePassword());
            tempCostReq.setParkingId(carParkInfo.getSuperviseParkingId());
        }
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("plateId",plateId);
        paramMap.put("vehicleType",1);
        String url = outOsShParking + "/service/parkinglot/download/reduces/" + tempCostReq.getParkingId();
        url = wrapperUrl(url,curTime,tempCostReq.getAppId(),tempCostReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,tempCostReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            JSONObject data = jsonObject.getJSONObject("data");
            JSONArray reduceJson = data.getJSONArray("reduceList");
            if (reduceJson == null) return BigDecimal.ZERO;
            List<ForeignCarShReduceResp> reduceList = reduceJson.toJavaList(ForeignCarShReduceResp.class);
            long entranceTime = inTime.getTime();
            for (ForeignCarShReduceResp reduce:reduceList){
                long reduceFrom = reduce.getReduceFrom();
                long reduceTo = reduce.getReduceTo();
                if (entranceTime >= reduceFrom && entranceTime <= reduceTo){
                    return reduce.getReduceMoney() == null ? BigDecimal.ZERO: new BigDecimal(reduce.getReduceMoney());
                }
            }
        }
        return BigDecimal.ZERO;
    }

    public Object reserves(ForeignCarShBase reservesReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("reserveDate", curTime);
        String url = outOsShParking + "/service/parkinglot/download/reserves/" + reservesReq.getParkingId();
        url = wrapperUrl(url,curTime,reservesReq.getAppId(),reservesReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,reservesReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            //
            return true;
        }
        return null;
    }

    public Object payment(ForeignCarShPaymentReq paymentReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("businessId", paymentReq.getBusinessId());
        paramMap.put("orderId", paymentReq.getOrderId());
        paramMap.put("plateId", paymentReq.getPlateId());
        paramMap.put("vehicleType",paymentReq.getVehicleType());
        paramMap.put("arrivedTime",paymentReq.getArrivedTime());
        paramMap.put("totalMoney",paymentReq.getTotalMoney());
        paramMap.put("reduceMoney",paymentReq.getReduceMoney());
        paramMap.put("reduceTime",paymentReq.getReduceTime());
        paramMap.put("reduceCode",paymentReq.getReduceCode());
        paramMap.put("dueMoney",paymentReq.getDueMoney());
        paramMap.put("validityQuoteTime",paymentReq.getValidityQuoteTime());
        paramMap.put("dataTime",curTime);
        String url = outOsShParking + "/service/parkinglot/submit/payment/" + paymentReq.getParkingId();
        url = wrapperUrl(url,curTime,paymentReq.getAppId(),paymentReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,paymentReq.getPassword());
        String code = jsonObject.getString("code");
        if ("0".equals(code)){
            return true;
        }
        return false;
    }

    /**
     * 平台支付结果查询 No5.3.5
     * @return
     */
    public JSONObject payResult(ForeignCarShPayResultReq payResultReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("businessId", payResultReq.getBusinessId());
        paramMap.put("orderId", payResultReq.getOrderId());
        paramMap.put("dataTime", curTime);
        String url = outOsShParking + "/service/parkinglot/query/payresult/" + payResultReq.getParkingId();
        url = wrapperUrl(url,curTime,payResultReq.getAppId(),payResultReq.getPassword());
        return restTemplateUtil.postForEntitySecret(paramMap,url,payResultReq.getPassword());
    }

    /**
     * 停车缴费对账单下载 No5.3.6
     * @param payResultsReq
     * @return
     */
    public JSONObject payResults(ForeignCarShPayResultsReq payResultsReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("payDate", payResultsReq.getPayDate());
        paramMap.put("dataTime", curTime);
        String url = outOsShParking + "/service/parkinglot/download/payresults/" + payResultsReq.getParkingId();
        url = wrapperUrl(url,curTime,payResultsReq.getAppId(),payResultsReq.getPassword());
        return restTemplateUtil.postForEntitySecret(paramMap,url,payResultsReq.getPassword());
    }


    public JSONObject billInfos(ForeignCarShPayResultsReq payResultsReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("billDate", payResultsReq.getPayDate());
        paramMap.put("dataTime", curTime);
        String url = outOsShParking + "/service/parkinglot/download/billinfos/" + payResultsReq.getParkingId();
        url = wrapperUrl(url,curTime,payResultsReq.getAppId(),payResultsReq.getPassword());
        return restTemplateUtil.postForEntitySecret(paramMap,url,payResultsReq.getPassword());
    }

    /**
     * 通知路径注册 No5.3.10
     * @param pathUrlReq
     * @return
     */
    public JSONObject pathUrl(ForeignCarShPathUrlReq pathUrlReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("urlType", pathUrlReq.getUrlType());
        paramMap.put("url",pathUrlReq.getUrl());
        paramMap.put("leftValidTime",pathUrlReq.getLeftValidTime());
        paramMap.put("dataTime",curTime);
        String url = outOsShParking + "/service/parkinglot/notify/pathurl/" + pathUrlReq.getParkingId();
        url = wrapperUrl(url,curTime,pathUrlReq.getAppId(),pathUrlReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,pathUrlReq.getPassword());
        return jsonObject;
    }

    /**
     * 配置参数查询 No5.3.11
     * @param baseReq
     * @return
     */
    public JSONObject params(ForeignCarShBase baseReq) {
        Map<String,Object> paramMap = new LinkedHashMap<>();
        long curTime = Calendar.getInstance().getTimeInMillis();
        paramMap.put("dataTime",curTime);
        String url = outOsShParking + "/service/parkinglot/download/params/" + baseReq.getParkingId();
        url = wrapperUrl(url,curTime,baseReq.getAppId(),baseReq.getPassword());
        JSONObject jsonObject = restTemplateUtil.postForEntitySecret(paramMap,url,baseReq.getPassword());
        return jsonObject;
    }




    /**
     * 停车业务编码
     */
    public String getSeq(String parkingId){
        //停车业务编码28位: 8位日期(YYYYMMDD) + 13位场库id(大写,不足13位前补0) + 7位序列号
        String sysDateTime =  StringUtils.sysDateTime("yyyyMMdd");
        while (parkingId.length() < 13){
            parkingId = 0 + parkingId;
        }
        String rand = redisUtil.daySeq(RedisKeyConstant.CAR_SEQ + parkingId,7);
        return sysDateTime + parkingId + rand;
    }

    /**
     * 拼接Url
     * @param url
     * @param curTime  请求时间 - 毫秒
     * @param appId
     * @param password
     * @return
     */
    private String wrapperUrl(String url,long curTime,String appId,String password){
        String nonce = StringUtils.createSn(5);
        url = url + "?appId=" + appId + "&nonce=" + nonce +"&curTime=" + (curTime/1000) + "&checkSum=" + SHA1Util.sha1(password + nonce + (curTime/1000));
//        log.info("请求url:{}",url);
        return url;
    }

}
